package httpd

import (
	"encoding/base64"
	"fhe-search-cloud/encsearch"
	"fhe-search-cloud/g"
	"fmt"
	"net/http"
	"strconv"

	"github.com/gin-gonic/gin"
)

func Start() {
	r := gin.Default()
	r.Use(LimitRequestBodySize())
	r.ForwardedByClientIP = true
	r.SetTrustedProxies([]string{"127.0.0.1", "192.168.1.2", "10.0.0.0/8"})
	SetupRouter(r)
	r.Run(fmt.Sprintf(":%d", g.GetConfig().HttpConfig.Port))
}

// LimitRequestBodySize 使用中间件来设置请求体的大小限制
func LimitRequestBodySize() gin.HandlerFunc {
	return func(c *gin.Context) {
		r := c.Request
		r.Body = http.MaxBytesReader(c.Writer, r.Body, 10<<20) // 10MB
		c.Next()                                               // 继续处理下一个中间件或处理器
	}
}

func SetupRouter(r *gin.Engine) {
	// 串同态检索
	r.GET("/StringFheEncSearch", StringFheEncSearchHandler)
	r.GET("/GetPlainTextByDocId", GetPlainTextByDocIdHandler)
	r.POST("/ExtractKeywords", ExtractKeywordsHandler)
	r.POST("/UploadEncFile", UploadEncFileHandler)
}

func StringFheEncSearchHandler(c *gin.Context) {
	searchStr := c.Query("search_str")
	c.JSON(http.StatusOK, encsearch.StringFheEncSearch(searchStr))
}

func GetPlainTextByDocIdHandler(c *gin.Context) {
	docIdStr := c.Query("doc_id")
	docId, err := strconv.Atoi(docIdStr)
	if err != nil {
		c.JSON(http.StatusBadRequest, "doc_id must be number.")
	} else {
		c.JSON(http.StatusOK, encsearch.GetPlainTextByDocId(docId))
	}
}

func ExtractKeywordsHandler(c *gin.Context) {
	type ExtractKeywordsReq struct {
		Content string `json:"content"`
	}
	var req ExtractKeywordsReq
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	content := req.Content
	keywords := encsearch.ExtractKeywords(content)
	c.JSON(http.StatusOK, keywords)
}

func UploadEncFileHandler(c *gin.Context) {
	type UploadEncFileReq struct {
		Title         string              `json:"title"`
		FileType      string              `json:"file_type"`
		ContentBase64 string              `json:"content_base64"`
		Keywords      []encsearch.Keyword `json:"keywords"`
	}
	var req UploadEncFileReq
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}
	content, err := base64.StdEncoding.DecodeString(req.ContentBase64)
	if err != nil {
		c.JSON(http.StatusBadRequest, "content must be base64 encoded.")
		return
	}
	err = encsearch.UploadEncFile(req.Title, req.FileType, content, req.Keywords)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
	} else {
		c.JSON(http.StatusOK, "success")
	}
}
